import { Decode } from "./Decode";
import http from "http";
import formidable from "formidable";
import fs from "fs";
import path from "path";

interface msgType {
  from: string;
  to: string;
  msg: string;
  handleKey: string
}

export interface Connection {
  send: (data: string) => void
}

type responseHandlerType = (...args: [msgType, ...args: any]) => void;
export class WebsocketServer {
  private ws = require("nodejs-websocket");
  private connections: { nickname: string; con: any }[] = [];
  private responseHandler: responseHandlerType;
  constructor(handler: responseHandlerType) {
    this.startServer();
    this.responseHandler = handler;
  }
  public send(msg: msgType) {
    const dest = this.connections.find((val) => val.nickname === msg.to);
    if (!dest) return;
    dest.con.send(JSON.stringify(msg));
  }
  // private assembleComponent(msg: string) {
  //   new Decode()
  // }
  private receive(obj: msgType, dest: Connection,) {
    // console.log("receive msg: " + JSON.stringify(msg));
    /**
     (data: string) => {
      dest.send(
        JSON.stringify({
          from: "server",
          to: from,
          msg: data,
        })
      );
    }
     */
    this.responseHandler(obj, dest);

    dest.send(
      JSON.stringify({
        from: "server",
        to: obj.from,
        msg: "ojbk",
      })
    );
  }
  private startServer() {
    this.ws
      .createServer((conn: any) => {
        let init: boolean = false;
        conn.on("text", (str: string) => {
          const obj = JSON.parse(str) as msgType;
          if (!init) {
            init = true;
            const exist = this.connections.find(
              (val) => val.nickname === obj.from
            );
            if (!exist)
              this.connections.push({ nickname: obj.from, con: conn });
            else exist.con = conn;
            console.log("new connection: " + obj.from);
          }
          if (obj.to === "server") {
            this.receive(obj, conn);
          } else this.send(obj);
        });
        conn.on("close", function (code: any, reason: any) {
          console.log(code, reason);
        });
        conn.on("error", function (code: any, reason: any) {
          console.log(code, reason);
        });
      })
      .listen(8080);
  }
  public closeServer() {
    this.connections.forEach((val) => val.con.close());
    this.ws.closeServer();
  }
}

export class Server {
  private resFolder: string;
  private server: http.Server | null = null;
  constructor(resFolder: string) {
    this.resFolder = resFolder;
  }
  public startServer() {
    this.server = http
      .createServer((req, res) => {
        if (req.url == "/upload") {
          const form = new formidable.IncomingForm();
          form.parse(req, (err, fields, files) => {
            if (!files.filetoupload) {
              console.log("error: file upload failed!");
              return;
            }
            const f = files.filetoupload[0];
            const oldpath = f.filepath;
            if (!f.originalFilename) {
              console.log("error: cannot get original file name!");
              return;
            }
            const newpath = path.join(this.resFolder, f.originalFilename);
            fs.rename(oldpath, newpath, function (err) {
              if (err) throw err;
              res.write("File uploaded and moved!");
              res.end();
            });
          });
        }
      })
      .listen(8081);
  }
  public closeServer() {
    if (!this.server) return;
    this.server.close();
  }
}
